15.1 Promise的含义
说明:Promise是异步编程的一种解决方案,比传统的解决方案——回调函数和事件,更合理和更强大
缺点:
- 一旦新建它就会立即执行,无法中途取消
- 如果不设置回调函数,
Promise内部抛出的错误,不会反应到外部 - 当处于
Pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)
扩展:如果某些事件不断地反复发生,一般来说,使用stream模式是比部署Promise更好的选择
Promise对象
说明:代表一个异步操作,有3个状态
Pending:进行中Resolved: 已完成Regected: 已失败
特点:两个特点
- 对象的状态不受外界影响
- 一旦状态改变,就不会再变,任何时候都可以得到这个结果
15.2 基本用法
Promise 构造函数
说明:Promise作为一个构造函数,用来生成Promise实例
| 参数 | 类型 | 说明 | 必需 |
|---|---|---|---|
resolver |
function |
该函数作为异步操作的处理函数 | 是 |
参数解释:resolver被调用时会传两个参数进来,它们都是函数
resolver函数: 调用该函数,将Promise对象的状态从“未完成”(Pending)变为“成功”(Resolved),在异步操作成功时调用,并将异步操作的结果,作为参数传递出去reject函数:调用该函数,将Promise对象的状态从“未完成”(Pending)变为“失败”(Rejected),在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去
Promise.prototype.then()
说明:可以用then方法分别指定Resolved状态和Reject状态的回调函数
Demo1: 用Promise对象实现的Ajax操作
1 | var getJSON = function(url) { |
15.3 Promise.prototype.then()
说明:为Promise实例添加状态改变时的回调函数
| 参数 | 类型 | 说明 | 必需 |
|---|---|---|---|
| 1 | function |
Resolved状态的回调函数 |
否 |
| 2 | function |
是Rejected状态的回调函数 |
否 |
返回值:一个新的Promise实例(注意,不是原来那个Promise实例)
1 | var getJSON = function(url) { |
15.4 Promise.prototype.catch()
说明:用于指定发生错误时的回调函数,相当于then只提供rejected状态的回调(Promise.prototype.then(null, rejection))
- 如果
Promise状态已经变成Resolved,再抛出错误是无效的 Promise对象的错误具有冒泡性质,会一直向后传递(所以链式调用中,位置靠后报错不会被位置靠前的catch捕获),直到被捕获为止跟传统的
try/catch代码块不同的是,如果没有使用catch方法指定错误处理的回调函数,Promise对象抛出的错误不会传递到外层代码,即不会有任何反应(Chrome浏览器不遵守这条规定,它会抛出错误“ReferenceError: x is not defined”。)catch方法之中,还能再抛出错误,如果后面还有catch,可以被捕获
| 参数 | 类型 | 说明 | 必需 |
|---|---|---|---|
| 1 | function |
发生错误时的回调函数 | 是 |
返回值:一个新的 promise 对象
建议:一般来说,不要在then方法里面定义Reject状态的回调函数(即then的第二个参数),总是使用catch方法
Demo1: 基本使用
1 | // getJSON方法返回一个Promise对象 |
Demo2: 调用 reject 等同于抛出错误
1 | // 写法一:通过 throw 抛出错误,触发 catch |
Demo3: Promise对象的错误具有“冒泡”性质,会一直向后传递,直到被捕获为止
1 | getJSON("/post/1.json") |
Demo4: catch 中也可以跑出错误
1 | var someAsyncThing = function() { |
15.5 Promise.all()
说明:用于将多个Promise实例,包装成一个新的Promise实例,新的Promise实例的状态和原本的一批Promise实例的状态之间的关系是
- 只有原本的一批
Promise实例的状态都变成fulfilled,新的Promise实例的状态才会变成fulfilled,此时原本的一批Promise实例的返回值组成一个数组,传递给p的回调函数 - 只要原本的一批
Promise实例之中有一个被rejected,新的Promise实例的状态就变成rejected,此时第一个被reject的实例的返回值,会传递给新的Promise实例的回调函数
| 参数 | 类型 | 说明 | 必需 |
|---|---|---|---|
| 1 | Iterator |
必须具有Iterator接口,且返回的每个成员都是Promise实例(如果不是,就会先调用Promise.resolve方法,将参数转为Promise实例) |
是 |
返回值:一个新的Promise实例
Demo1: 基本使用
1 | // 生成一个Promise对象的数组 |
Demo2: 两个异步操作
1 | const databasePromise = connectDatabase(); |
15.6 Promise.race()
说明:用于将多个Promise实例,包装成一个新的Promise实例,新的Promise实例的状态和原本的一批Promise实例的状态之间的关系是
- 只要原本的一批
Promise实例之中有一个实例率先改变状态,新的Promise实例的状态就跟着改变。那个率先改变的Promise实例的返回值,就传递给新的Promise实例的回调函数
参数:和Promise.all()完全一致
Demo: 如果指定时间内没有获得结果,就将Promise的状态变为reject,否则变为resolve
1 | var p = Promise.race([ |
15.7 Promise.resolve()
说明:将现有对象转为Promise对象(状态不一定就是resolved)
技巧:如果希望得到一个Promise对象,比较方便的方法就是直接调用Promise.resolve方法
| 参数 | 类型 | 说明 | 必需 |
|---|---|---|---|
| 1 | [Promise/thenable/普通object或基本类型] |
参数分成四种情况,下面详细讨论 | 否 |
| 情形 | 参数说明 | Promise.resolve()行为 |
|---|---|---|
| 1) | Promise实例 |
原封不动地返回这个实例 |
| 2) | thenable对象(具有then方法的对象) |
将这个对象转为Promise对象 |
| 3) | 普通object或基本类型 |
返回一个新的Promise对象,状态为Resolved,并将该参数传递 |
| 4) | 没有参数 | 直接返回一个Resolved状态的Promise对象 |
注意:情形3)和4)中,状态的改变(变为Resolved)发生在本轮时间循环结束时
Demo1: 基本使用
1 | Promise.resolve('foo') |
Demo2 情形2
1 | /** |
Demo3: 情形3
1 | var p = Promise.resolve('Hello'); |
Demo4: 情形4
1 | // 插入到下一轮事件循环的开头 |
15.8 Promise.reject()
说明:也会返回一个新的 Promise实例,该实例的状态为rejected
参数:和Promise.resolved()完全一致
1 | var p = Promise.reject('出错了'); |
15.9 两个有用的附加方法
说明:不是Promise API提供的方法,需要自己部署
done()
说明:总是处于回调链的尾端,保证抛出任何可能出现的错误
参数:和Promise.prototype.then()完全一致
部署
1 | Promise.prototype.done = function (onFulfilled, onRejected) { |
使用
1 | asyncFunc() |
finally()
说明:总是处于回调链的尾端,用于指定不管Promise对象最后状态如何,都会执行的操作
| 参数 | 类型 | 说明 | 必需 |
|---|---|---|---|
| 1 | function |
该函数不管怎样都必须执行 | 是 |
部署
1 | Promise.prototype.finally = function (callback) { |
使用:服务器使用Promise处理请求,然后使用finally方法关掉服务器
1 | server.listen(0) |
15.10 应用
加载图片
1 | const preloadImage = function (path) { |
Generator函数与Promise的结合
1 | function getFoo () { |